package net.linlan.stage.api;

import java.util.Set;

import net.linlan.man.admin.dto.AdminUserDto;
import net.linlan.man.admin.service.AdminUserService;
import net.linlan.annotation.Encrypt;
import net.linlan.frame.FrameAdminUser;
import net.linlan.plat.comm.manager.AsyncManager;
import net.linlan.plat.comm.manager.factory.AsyncFactory;
import net.linlan.plat.comm.service.AdminLoginService;
import net.linlan.plat.comm.service.TokenService;
import net.linlan.plat.view.admin.manager.AdminMenuManager;
import net.linlan.plat.comm.service.SysPermissionService;
import net.linlan.plat.comm.vo.AppLoginInfo;
import net.linlan.plat.view.admin.vo.AppPageIndexInfo;
import net.linlan.plat.view.admin.vo.AppUserInfo;
import net.linlan.sys.web.RedisService;
import net.linlan.sys.web.KernelConstant;
import net.linlan.commons.core.StringUtils;
import net.linlan.utils.MessageUtils;
import net.linlan.utils.constant.CacheConstants;
import net.linlan.utils.constant.Constants;
import net.linlan.utils.exception.user.CaptchaException;
import net.linlan.utils.exception.user.CaptchaExpireException;
import net.linlan.plat.view.admin.vo.AdminUserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import net.linlan.commons.core.ResponseResult;
import net.linlan.man.web.model.LoginBody;

import static net.linlan.man.web.SecurityUtils.getLoginUser;

/**
 * 登录验证
 *
 * @author Linlan
 */
@RestController
public class SysLoginController
{
    @Autowired
    private AdminLoginService sysLoginService;
    @Autowired
    private AdminMenuManager adminMenuManager;
    @Autowired
    private SysPermissionService permissionService;
    @Autowired
    private AdminUserService adminUserService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private RedisService redisService;

    /**
     * 登录方法
     *
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/login")
    @Encrypt
    public ResponseResult<AppLoginInfo> login(@RequestBody LoginBody loginBody)
    {
        // 生成令牌
        AppLoginInfo appLoginInfo = sysLoginService.login(loginBody.getUsername(), loginBody.getPassword(),
                loginBody.getCode(), loginBody.getUuid(), loginBody.getAppId());
        return ResponseResult.ok(appLoginInfo);
    }

    /**
     * 获取应用用户信息，作用于Work端登录之后进行用户基本信息获取
     *
     * @return 用户信息
     */
    @GetMapping("appUserInfo")
    @Encrypt
    public ResponseResult<AppUserInfo> appUserInfo()
    {
        FrameAdminUser loginUser = getLoginUser();
        AdminUserDto user = adminUserService.selectUserByUsername(loginUser.getUsername());
        // 角色集合
        Set<String> roles = permissionService.getRolePermission(user);
        // 权限集合
        Set<String> permissions = permissionService.getMenuPermission(user);

        AppUserInfo appUserInfo = new AppUserInfo();
        appUserInfo.setUser((AdminUserVo) AdminUserVo.DTO.apply(user));
        appUserInfo.setRoles(roles);
        appUserInfo.setPermissions(permissions);
        if (!loginUser.getPerms().equals(permissions))
        {
            loginUser.setPerms(permissions);
            tokenService.refreshToken(loginUser);
        }
        return ResponseResult.ok(appUserInfo);
    }

    /**
     * 获取应用首页信息，包括菜单含路由信息
     *
     * @return 路由信息
     */
    @GetMapping("appIndexInfo")
    @Encrypt
    public ResponseResult<AppPageIndexInfo> appIndexInfo()
    {
        FrameAdminUser loginUser = getLoginUser();
        AppPageIndexInfo appPageIndexInfo = adminMenuManager.getAppPageIndexInfo(loginUser);
        return ResponseResult.ok(appPageIndexInfo);
    }


    /**
     * 登录方法
     *
     * @param loginBody 登录信息
     * @return 结果
     */
    @PostMapping("/thirdOrgan/login")
    @Encrypt
    public ResponseResult<AppLoginInfo> thirdOrganLogin(@RequestBody LoginBody loginBody)
    {
        // 生成令牌
        AppLoginInfo appLoginInfo = sysLoginService.thirdUserlogin(loginBody.getUsername(),
                loginBody.getPassword(), loginBody.getCode(), loginBody.getUuid(), loginBody.getAppId());
        return ResponseResult.ok(appLoginInfo);
    }

    /**
     * 校验验证码
     * @param code  验证码
     * @param uuid  临时UUID
     * @return 验证结果
     */
    @GetMapping("captcha/verify")
    @Encrypt
    public ResponseResult<String> validateCaptcha(String code, String uuid)
    {

        FrameAdminUser loginUser = getLoginUser();
        String username = loginUser.getUsername();
        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
        String captcha = redisService.get(verifyKey);
        if (captcha == null)
        {
            AsyncManager.me().execute(AsyncFactory.saveAdminLoginLog(KernelConstant.DEFAULT_BIGINT, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"), loginUser.getAppId()));
            throw new CaptchaExpireException();
        }
        if (!code.equalsIgnoreCase(captcha))
        {
            AsyncManager.me().execute(AsyncFactory.saveAdminLoginLog(KernelConstant.DEFAULT_BIGINT, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"), loginUser.getAppId()));
            throw new CaptchaException();
        }

        return ResponseResult.ok();
    }

}
